//
//  NetworkManager.swift
//  GHMoyaNetWorkTest
//
//  Created by Guanghui Liao on 4/2/18.
//  Copyright © 2018 liaoworking. All rights reserved.
//

import Foundation
import Moya
import Alamofire
import SwiftyJSON
/// 超时时长
private var requestTimeOut:Double = 30
///成功数据的回调
typealias successCallback = ((JSON,Int,String) -> (Void))
///失败的回调
typealias failedCallback = ((String,String,String) -> (Void))
///网络错误的回调
typealias errorCallback = (() -> (Void))

/// -- cocoa
struct succeedMode {
    
    var jsonData:JSON? = nil
    var code:Int = -1
    var message = "失败信息"
}

struct failedMode {
    
    var code:Int = -1
    var message = "失败信息"
}

///成功数据的回调
typealias NetworkSucceed = ((succeedMode) -> (Void))
///失败的回调
typealias NetworkFailed = ((failedMode) -> (Void))


///网络请求的基本设置,这里可以拿到是具体的哪个网络请求，可以在这里做一些设置
private let myEndpointClosure = { (target: API) -> Endpoint in
    ///这里把endpoint重新构造一遍主要为了解决网络请求地址里面含有? 时无法解析的bug
    let url = target.baseURL.absoluteString + target.path
    var task = target.task
    
    var endpoint = Endpoint(
        url: url,
        sampleResponseClosure: { .networkResponse(200, target.sampleData) },
        method: target.method,
        task: task,
        httpHeaderFields: target.headers
    )
    requestTimeOut = 60//每次请求都会调用endpointClosure 到这里设置超时时长 也可单独每个接口设置
    switch target {
    case .baseRequset:
        requestTimeOut = 10
        return endpoint
    case .register:
        requestTimeOut = 10
        return endpoint
        
    default:
        return endpoint
    }
}

///网络请求的设置
private let requestClosure = { (endpoint: Endpoint, done: MoyaProvider.RequestResultClosure) in
    do {
        var request = try endpoint.urlRequest()
        //设置请求时长
        request.timeoutInterval = requestTimeOut
        request.httpShouldHandleCookies = true
        let nsObject = Bundle.main.infoDictionary?["CFBundleShortVersionString"]
        let version = nsObject as! NSString
        request.setValue("ManbetX iOS", forHTTPHeaderField: "User-Agent")
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")

        // 打印请求参数
        if let requestData = request.httpBody {
            print("!!!\(request.url!)"+"\n"+"\(request.httpMethod ?? "")"+"发送参数"+"\(String(data: request.httpBody!, encoding: String.Encoding.utf8) ?? "")")
        }else{
            print("!!\(request.url!)"+"\(String(describing: request.httpMethod))")
        }
        done(.success(request))
    } catch {
        done(.failure(MoyaError.underlying(error, nil)))
    }
}

/// NetworkActivityPlugin插件用来监听网络请求，界面上做相应的展示
///但这里我没怎么用这个。。。 loading的逻辑直接放在网络处理里面了
private let networkPlugin = NetworkActivityPlugin.init { (changeType, targetType) in

    print("networkPlugin \(changeType)")
    //targetType 是当前请求的基本信息
    switch(changeType){
    case .began:
        print("开始请求网络")
        
    case .ended:
        print("结束")
    }
}

// https://github.com/Moya/Moya/blob/master/docs/Providers.md  参数使用说明
//stubClosure   用来延时发送网络请求


////网络请求发送的核心初始化方法，创建网络请求对象
let Provider = MoyaProvider<API>(endpointClosure: myEndpointClosure, requestClosure: requestClosure, plugins: [networkPlugin], trackInflights: false)



/// 最常用的网络请求，只需知道正确的结果无需其他操作时候用这个
///
/// - Parameters:
///   - target: 网络请求
///   - completion: 请求成功的回调
func NetWorkRequest(_ target: API, completion: @escaping successCallback ){
    NetWorkRequest(target, completion: completion, failed: nil, errorResult: nil)
}


/// 需要知道成功或者失败的网络请求， 要知道code码为其他情况时候用这个
///
/// - Parameters:
///   - target: 网络请求
///   - completion: 成功的回调
///   - failed: 请求失败的回调
func NetWorkRequest(_ target: API, completion: @escaping successCallback , failed:failedCallback?) {
    NetWorkRequest(target, completion: completion, failed: failed, errorResult: nil)
}




///  需要知道成功、失败、错误情况回调的网络请求   像结束下拉刷新各种情况都要判断
///
/// - Parameters:
///   - target: 网络请求
///   - completion: 成功
///   - failed: 失败
///   - error: 错误
func NetWorkRequest(_ target: API, completion: @escaping successCallback , failed:failedCallback?, errorResult:errorCallback?) {
    //先判断网络是否有链接 没有的话直接返回--代码略
    if !isNetworkConnect{
        print("提示用户网络似乎出现了问题")
        if(failed != nil){
            failed!("网络异常","504","网络异常")
        }
        return
    }
    //这里显示loading图
    Provider.request(target) { (result) in
        //隐藏hud
        
        switch result {
        case let .success(response):
            do {
//                response.statusCode
                let statusCode = response.statusCode // 响应状态码：200, 401, 500...
//                let data = response.data // 响应数据
                 print("状态码\(statusCode)")
                let jsonData = JSON(response.data)
                
                let strData = String(data: response.data, encoding: String.Encoding.utf8) ?? ""
                print("\(response.data),\(String(data: response.data, encoding: String.Encoding.utf8) ?? "")")
                print(jsonData)
                if jsonData[RESULT_CODE].stringValue == "0" || jsonData[RESULT_CODE].stringValue == "1007"{
                    completion(jsonData,statusCode,strData)
                }else{
                    if failed != nil{
                        if jsonData == JSON.null && strData != ""{
                             failed!(strData,"-1",strData)
                        }else{
                            if jsonData[RESULT_MESSAGE].stringValue == "" {failed!(jsonData[RESULT_ERROR].stringValue,jsonData[RESULT_CODE].stringValue,jsonData[RESULT_ERROR].stringValue)
                            }else{
                                failed!(jsonData[RESULT_MESSAGE].stringValue,jsonData[RESULT_CODE].stringValue,jsonData[RESULT_MESSAGE].stringValue)
                            }
                        }
                    }
                }
                
            } catch {
                
            }
        case let .failure(error):
          //  print("\(error)")
            switch error{
            case .imageMapping(let response):
                print("错误原因1：\(error.errorDescription ?? "") \(response.statusCode)")
                print(response)
            case .jsonMapping(let response):
                print("错误原因2：\(error.errorDescription ?? "") \(response.statusCode)")
                print(response)
            case .stringMapping(let response):
                print("错误原因3：\(error.errorDescription ?? "") \(response.statusCode)")
                print(response)
            case .objectMapping( _, let response):
         //       print("错误原因：\(errors.errorDescription ?? "")")
                print(response)
            case .encodableMapping( _):
                print("错误原因4：\(error.errorDescription ?? "")")
            case .statusCode( _):
                print("错误原因5：\(error.errorDescription ?? "")")
            case .underlying( _, _):
                print("错误原因6：\(error.errorDescription ?? "") === \(target.baseURL)\(target.path)")
            case .requestMapping( _):
                print("错误原因7：\(error.errorDescription ?? "")")
            case .parameterEncoding( _):
                print("错误原因8：\(error.errorDescription ?? "") ")
            }
   
            guard (error as? CustomStringConvertible) != nil else {
                //网络连接失败，提示用户
                print("网络连接失败")
                break
            }
            if errorResult != nil {
                errorResult!()
            }
        }
    }
}

/// 基于Alamofire,网络是否连接，，这个方法不建议放到这个类中,可以放在全局的工具类中判断网络链接情况
/// 用get方法是因为这样才会在获取isNetworkConnect时实时判断网络链接请求，如有更好的方法可以fork
var isNetworkConnect: Bool {
    get{
        let network = NetworkReachabilityManager()
        return network?.isReachable ?? true //无返回就默认网络已连接
    }
}


/// 新定义针对1.0版本的网络请求
///
/// - Parameters:
///   - target: 网络请求
///   - success: 请求成功的回调
///   - failure: 请求失败的回调

func NetWorkRequestOld(_ target: API, success: NetworkSucceed?, failure: NetworkFailed?) {
    
    //先判断网络是否有链接 没有的话直接返回
    if !isNetworkConnect{
        print("NetWorkRequestOld -- 网络是未链接")
        if(failure != nil){
            failure!(.init(code: 504, message: "网络异常"))
        }
        return
    }
    
    Provider.request(target) { (result) in
        switch result {
        case let .success(response):
            // response.statusCode
            // response.data // 响应数据
            let statusCode = response.statusCode // 响应状态码：200, 401, 500...
            let jsonData = JSON(response.data)
            let strData = String(data: response.data, encoding: String.Encoding.utf8) ?? ""
            print("状态码：\(statusCode)")
            print("jsonData:",jsonData)
            
            if jsonData[RESULT_CODE].stringValue == "0" || jsonData[RESULT_CODE].stringValue == "1007"{
                // 请求成功
                success!(.init(jsonData: jsonData, code: statusCode, message: jsonData[RESULT_MESSAGE].stringValue))
                
            }else {
                // 请求失败
                if failure != nil{
                   if jsonData == JSON.null && strData != ""{
                    
                        failure!(.init(code: -1, message: strData))
                        
                   }else{
                       if jsonData[RESULT_MESSAGE].stringValue == "" {
                        
                        failure!(.init(code: jsonData[RESULT_CODE].intValue, message: jsonData[RESULT_ERROR].stringValue))
                        
                       }else{
                        
                          failure!(.init(code: jsonData[RESULT_CODE].intValue, message: jsonData[RESULT_MESSAGE].stringValue))
                        
                       }
                   }
               }
           }
            // 请求失败
            case let .failure(error):
                
                failure!(.init(code: -1, message:(error.errorDescription ?? "")))
                switch error{
                case .imageMapping(let response):
                    print("错误原因1：\(error.errorDescription ?? "") \(response.statusCode)")
                    print(response)
                case .jsonMapping(let response):
                    print("错误原因2：\(error.errorDescription ?? "") \(response.statusCode)")
                    print(response)
                case .stringMapping(let response):
                    print("错误原因3：\(error.errorDescription ?? "") \(response.statusCode)")
                    print(response)
                case .objectMapping( _, let response):
             //       print("错误原因：\(errors.errorDescription ?? "")")
                    print(response)
                case .encodableMapping( _):
                    print("错误原因4：\(error.errorDescription ?? "")")
                case .statusCode( _):
                    print("错误原因5：\(error.errorDescription ?? "")")
                case .underlying( _, _):
                    print("错误原因6：\(error.errorDescription ?? "") === \(target.baseURL)\(target.path)")
                case .requestMapping( _):
                    print("错误原因7：\(error.errorDescription ?? "")")
                case .parameterEncoding( _):
                    print("错误原因8：\(error.errorDescription ?? "") ")
                }
       
            }
    }
}




































